// Copyright 2007-2010 Comdiv (F. Sadykov) - http://code.google.com/u/fagim.sadykov/
// Supported by Media Technology LTD 
//  
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 
// MODIFICATIONS HAVE BEEN MADE TO THIS FILE
using System;
using System.Security.Principal;
using System.Threading;
using System.Web;
using Comdiv.Design;
using Comdiv.Extensions;
using Comdiv.Application;
using System.Xml.Linq;
using System.Collections.Generic;
using Comdiv.IO;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Linq;

namespace Comdiv.Security{
    ///<summary>
    ///</summary>
    public class DefaultPrincipalSource: IPrincipalSource{
        public DefaultPrincipalSource() {
            myapp.OnReload += new Common.EventWithDataHandler<object, int>(myapp_OnReload);
        }

        void myapp_OnReload(object sender, Common.EventWithDataArgs<int> args){
            rewrites = null;
            rewriterules.Clear();
        }
        [ThreadStatic] public static IPrincipal _current;
        public object lockSync = new object();
        public IImpersonation Impersonation { get; set; }

        #region IPrincipalSourceService Members

        public IPrincipal Current{
            get{
                lock (lockSync){
                    checkThread();
                    if (Impersonation != null){
                        return Impersonation.Resolve(_current);
                    }
                    return _current;
                }
            }
        }

        public IPrincipal BasePrincipal{
            get{
                lock (lockSync){
                    checkThread();
                    return _current;
                }
            }
            set{
                lock (lockSync){
                    _current = value;
                }
            }
        }

        #endregion

        

        private void checkThread(){
            if (null == _current){
                _current =
                    getHttpUser()
                    ??
                    Thread.CurrentPrincipal;
            }
        }
        struct replacer{
            public string regex;
            public string replace;
        }

        private IList<replacer> rewrites;
        protected void checkRewrites() {
            if (null == rewrites) {
                rewriterules.Clear();
                var file =  myapp.files.Read("~/usr/security.map.config");
                var rewritesx = XElement.Parse(file).XPathSelectElements("./rewrite").ToArray();
                rewrites = new List<replacer>();
                foreach (var x in rewritesx){
                    var r = new replacer();
                    r.regex = x.attr("regex");
                    r.replace = x.attr("replace");
                    rewrites.Add(r);
                }
                
            }
        }

        protected string resolveRewrite(string name) {

            if (rewriterules.ContainsKey(name)) {
                return rewriterules[name];
            }
            var realname = name;
            foreach (var r in rewrites) {
                var regex = r.regex;
                var repl = r.replace;
                realname = realname.replace(regex, repl);
            }
            rewriterules[name] = realname;
            return realname;

        }

        IDictionary<string, string> rewriterules = new Dictionary<string, string>();


        [NoCover("cannot reproduce behaviour of httpcontext.current in test environment")]
        protected IPrincipal getHttpUser(){
            if (HttpContext.Current == null){
                return null;
            }
            if (HttpContext.Current.User == null){
                return new GenericPrincipal(new GenericIdentity("STARTUP_APP_USER"), new[]{"ADMIN"});
            }
            if (HttpContext.Current.User.Identity.Name.noContent()){
                return new GenericPrincipal(new GenericIdentity("GUEST"), new[]{"DEFAULT"});
            }
            checkRewrites();
            var name = HttpContext.Current.User.Identity.Name;
            var realname = resolveRewrite(name);
            if (name == realname) return HttpContext.Current.User;
            return new GenericPrincipal(new GenericIdentity(realname), new[] { "DEFAULT" });

        }
    }
}